package net.ib.mtalk.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;
import android.location.Location;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.Thumbnails;

import com.android.camera.Util;

public class ImageManager {
public static final int IMAGE_SAMPLING_SQUARE = 8;
	
	public static String uriFromData(Context parentContext, byte[] data, int maxLength) {
    	BitmapFactory.Options options = new BitmapFactory.Options();
		
    	Bitmap preparedPhoto = null;
    	
    	int sampleSquare = IMAGE_SAMPLING_SQUARE;
		do {
			if (preparedPhoto != null && !preparedPhoto.isRecycled()) {
				preparedPhoto.recycle();
				System.gc();
			}
			
			if (sampleSquare == 0) maxLength = 0;
			
			options.inSampleSize = (int) Math.pow(2, sampleSquare);
			
			preparedPhoto = BitmapFactory.decodeByteArray(data, 0, data.length, options);
			if(preparedPhoto == null) return null;
			
			int majorAxis = (preparedPhoto.getWidth() > preparedPhoto.getHeight())? preparedPhoto.getWidth() : preparedPhoto.getHeight();
			
			if(sampleSquare > 0) sampleSquare -= (int)(Math.log(maxLength / majorAxis) / Math.log(2));
			else sampleSquare = 0;
			
			if(maxLength <= 0) break;
		} while(preparedPhoto.getWidth() < maxLength / 2 && preparedPhoto.getHeight() < maxLength / 2);
		
		return MediaStore.Images.Media.insertImage(parentContext.getContentResolver(), preparedPhoto, "AutoGuard", "");
    }
	
	public static final int IMAGE_THUMB_SIZE	= 100;
	
	/**
	 * 파일로부터 작은 이미지를 만들어낸다.<br>
	 * <br>
	 * 사이즈로 주어진 크기보다 크되, 가능한한 작은 크기의 이미지를 로딩한다.
	 * 이미지 크기의 감쇠는 가로세로 각각 절반씩으로 해상도를 줄여가며 체크한다.<br>
	 * <br>
	 * 이 함수는 컨텐츠 저장소를 사용하지 않고 BitmapFactory만을 이용한다.
	 * @param file 대상 파일
	 * @param minSize pixel. 원하는 최소 크기의 가로세로 정사각형 범위. 이 크기보다는 작지 않으면서 가능한한 작은 이미지를 만들게 된다.
	 * @return 만들어진 비트맵
	 */
	public static Bitmap getFloorThumbnail(File file, int minSize) {
	    try {
	        //Decode image size
	        BitmapFactory.Options o = new BitmapFactory.Options();
	        o.inJustDecodeBounds = true;
	        BitmapFactory.decodeStream(new FileInputStream(file),null,o);

	        //Find the correct scale value. It should be the power of 2.
	        int width_tmp=o.outWidth, height_tmp=o.outHeight;
	        int scale=1;
	        while(true){
	            if(width_tmp/2<minSize || height_tmp/2<minSize)
	                break;
	            width_tmp/=2;
	            height_tmp/=2;
	            scale*=2;
	        }

	        //Decode with inSampleSize
	        BitmapFactory.Options o2 = new BitmapFactory.Options();
	        o2.inSampleSize=scale;
	        return BitmapFactory.decodeStream(new FileInputStream(file), null, o2);
	    } catch (FileNotFoundException e) {}
	    return null;
	}
	
	public static Bitmap getFloorThumbnail(Bitmap bitmap, int minSize) {
        //Find the correct scale value. It should be the power of 2.
        int width_tmp=bitmap.getWidth(), height_tmp=bitmap.getHeight();
        int scale=1;
        while(true){
            if(width_tmp/2<minSize || height_tmp/2<minSize)
                break;
            width_tmp/=2;
            height_tmp/=2;
            scale*=2;
        }

		return Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/scale, bitmap.getHeight()/scale, true);
	}
	
	public static Bitmap getThumbnail(Context parentContext, Uri uri) {
		
		Bitmap preparedPhoto = null;
		
		InputStream photoStream = null;
		BitmapFactory.Options options = new BitmapFactory.Options();
		
		try {
			photoStream = parentContext.getContentResolver().openInputStream(uri);
			options.inSampleSize = IMAGE_SAMPLING_SQUARE;
			options.inDither = true;
			options.outHeight = IMAGE_THUMB_SIZE;
			options.outWidth = IMAGE_THUMB_SIZE;
			options.outMimeType = "mimeimage/jpeg";
			preparedPhoto = BitmapFactory.decodeStream(photoStream, null, options);
			
			if(preparedPhoto != null/* && getMajorAxis(preparedPhoto) > 150*/) {
				preparedPhoto = getResizedBitmap(preparedPhoto, IMAGE_THUMB_SIZE);
			}
		} catch (Exception e) {
			MTalkLogWriter.e(e);
			
		} finally {
			try {
				if(photoStream!=null) 
					photoStream.close();
				photoStream = null;
			} catch (IOException e) {
				MTalkLogWriter.e(e);
			}
		}
		return preparedPhoto;
	}
	
	public static Bitmap getResizedBitmap(Bitmap bitmap, int maxLength) {
		Bitmap result = null;
		
		int originalWidth = bitmap.getWidth();
		int originalHeight = bitmap.getHeight();
		
		if(originalHeight >= originalWidth) {
			int scaledWidth = maxLength * originalWidth / originalHeight;
			result = Bitmap.createScaledBitmap(bitmap, scaledWidth, maxLength, true);
		}
		else {
			int scaledHeight = maxLength * originalHeight / originalWidth;
			result = Bitmap.createScaledBitmap(bitmap, maxLength, scaledHeight, true);
		}
		bitmap.recycle();
		return result;
	}
	
	//
    // Stores a bitmap or a jpeg byte array to a file (using the specified
    // directory and filename). Also add an entry to the media store for
    // this picture. The title, dateTaken, location are attributes for the
    // picture. The degree is a one element array which returns the orientation
    // of the picture.
    //
    public static Uri addImage(ContentResolver cr, String title, long dateTaken,
            Location location, String directory, String filename,
            Bitmap source, byte[] jpegData, int[] degree) {
        // We should store image data earlier than insert it to ContentProvider,
        // otherwise we may not be able to generate thumbnail in time.
        OutputStream outputStream = null;
        String filePath = directory + "/" + filename;
        try {
            File dir = new File(directory);
            if (!dir.exists()) dir.mkdirs();
            File file = new File(directory, filename);
            outputStream = new FileOutputStream(file);
            if (source != null) {
                source.compress(CompressFormat.JPEG, 75, outputStream);
                degree[0] = 0;
            } else {
                outputStream.write(jpegData);
            }
        } catch (FileNotFoundException ex) {
        	MTalkLogWriter.e(ex);
            return null;
        } catch (IOException ex) {
        	MTalkLogWriter.e(ex);
            return null;
        } finally {
            Util.closeSilently(outputStream);
        }

        // Read back the compressed file size.
        long size = new File(directory, filename).length();

        ContentValues values = new ContentValues();
        values.put(Images.Media.TITLE, title);

        // That filename is what will be handed to Gmail when a user shares a
        // photo. Gmail gets the name of the picture attachment from the
        // "DISPLAY_NAME" field.
        values.put(Images.Media.DISPLAY_NAME, filename);
        values.put(Images.Media.DATE_TAKEN, dateTaken);
        values.put(Images.Media.MIME_TYPE, "image/jpeg");
        values.put(Images.Media.ORIENTATION, degree[0]);
        values.put(Images.Media.DATA, filePath);
        values.put(Images.Media.SIZE, size);

        if (location != null) {
            values.put(Images.Media.LATITUDE, location.getLatitude());
            values.put(Images.Media.LONGITUDE, location.getLongitude());
        }

        return cr.insert(STORAGE_URI, values);
    }
    
    private static final Uri STORAGE_URI = Images.Media.EXTERNAL_CONTENT_URI;
    
    public static int getExifOrientation(String filepath) {
        int degree = 0;
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
        } catch (IOException ex) {
        	MTalkLogWriter.e(ex);
        }
        if (exif != null) {
            int orientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION, -1);
            if (orientation != -1) {
                // We only recognize a subset of orientation tag values.
                switch(orientation) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        degree = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        degree = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        degree = 270;
                        break;
                }

            }
        }
        return degree;
    }
    
    public static Bitmap createMirrorImage(Bitmap originalImage) {
		// The gap we want between the reflection and the original image
		final int reflectionGap = 2;

		int width = originalImage.getWidth();
		int height = originalImage.getHeight();

		// This will not scale but will flip on the Y axis
		Matrix matrix = new Matrix();
		matrix.preScale(1, -1);

		// Create a Bitmap with the flip matix applied to it.
		// We only want the bottom half of the image
		Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
				height / 2, width, height / 2, matrix, false);

		// Create a new bitmap with same width but taller to fit reflection
		Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
				(height + height / 2), Config.ARGB_8888);

		// Create a new Canvas with the bitmap that's big enough for
		// the image plus gap plus reflection
		Canvas canvas = new Canvas(bitmapWithReflection);
		// Draw in the original image
		canvas.drawBitmap(originalImage, 0, 0, null);
		// Draw in the gap
		Paint deafaultPaint = new Paint();
		canvas.drawRect(0, height, width, height + reflectionGap,
				deafaultPaint);
		// Draw in the reflection
		canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);

		// Create a shader that is a linear gradient that covers the
		// reflection
		Paint paint = new Paint();
		LinearGradient shader = new LinearGradient(0,
				originalImage.getHeight(), 0,
				bitmapWithReflection.getHeight() + reflectionGap,
				0xa0ffffff, 0x00ffffff, TileMode.CLAMP);
		// Set the paint to use this shader (linear gradient)
		paint.setShader(shader);
		// Set the Transfer mode to be porter duff and destination in
		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		// Draw a rectangle using the paint with our linear gradient
		canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
				+ reflectionGap, paint);

		// Create an Image view and add our bitmap with reflection to it
		return bitmapWithReflection;
	}
    
	public static Bitmap getThumbnail(File p_File, Activity p_activity) {
		long imageID = getImageID(p_File, p_activity);
		if (imageID < 0) {
			return null;
		}
		return MediaStore.Images.Thumbnails.getThumbnail(
				p_activity.getContentResolver(), imageID,
				Thumbnails.MICRO_KIND, null);
	}

	public static long getImageID(File p_File, Activity p_activity) {
		long result = -1;
		Cursor c = p_activity.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
			    new String[]{ MediaStore.Images.Media._ID +"" },
			    MediaStore.Images.Media.DATA + "=?",
			    new String[]{ p_File.getAbsolutePath() },
			    null);
		c.moveToNext();
		if (!c.isAfterLast()) {
			result = c.getLong(0);
		}
		c.close();
		return result;
	}
	
	
}
